package com.ruihang.generalibrary.db;

import android.os.AsyncTask;
import android.text.TextUtils;

import com.jiongbull.jlog.JLog;

import org.xutils.DbManager;
import org.xutils.db.Selector;
import org.xutils.ex.DbException;
import org.xutils.x;

import java.util.List;

/**
 * 数据库查询工具类，后台子线程默认使用@link{AsyncTask}的线程池
 * Created by liuyu on 2016/9/18.
 */
public class DBUtils {

    private static DBUtils instance;

    private DbManager dbManager;

    private DbManager.DaoConfig daoConfig;

    private static final int CURRENT_DB_VERSION = 1;

    public static DBUtils getInstance() {
        if (instance == null) {
            instance = new DBUtils();
        }
        return instance;
    }

    private DBUtils() {
        daoConfig = new DbManager.DaoConfig().setDbName("scfocus2.db").setDbVersion(CURRENT_DB_VERSION)
                .setDbUpgradeListener(new DbManager.DbUpgradeListener() {
                    @Override
                    public void onUpgrade(DbManager db, int oldVersion, int newVersion) {
                        JLog.e(" in db upload old v " + oldVersion + "  new v " + newVersion);
                        if (newVersion == CURRENT_DB_VERSION) {

                            boolean b = true;
                            if (b) {
                                if (newVersion < 8) {
//                            List<NewsData> li = findListByColumn(NewsData.class, new String[]{"collectDate"}, new String[]{"<>"}, null, "collectDate", true);
//                            try {
//                                db.dropTable(NewsData.class);
//                                if (li != null && li.size() > 0) {
//                                    db.save(li);
//                                }
//                            } catch (Exception e) {
//                                e.printStackTrace();
//                            }
                                }
                                try {
//                            db.dropTable(XCLivingData.class);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                return;
                            }

                            try {
//                        db.addColumn(NewsData.class,"readDate");

                                if (oldVersion < newVersion - 2) {
//                            db.execNonQuery("alter table NewsData add readDate INTEGER ");
//                            addColumn(db,NewsData.class,"readDate");
//                            addColumn(db,NewsData.class,"itemType");
//                            addColumn(db, NewsData.class, "relevanceType");
//                            addColumn(db, NewsData.class, "relevanceId");
//                            addColumn(db, NewsData.class, "parentUrl");
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
        dbManager = x.getDb(daoConfig);
    }

    public DbManager getDbManager() {
        return dbManager;
    }

    public <T> void replaceAxync(T t) {
        if (t == null) {
            return;
        }
        AsyncTask.execute(new DbRunable<T>(t) {
            @Override
            public void run() {
                try {
                    JLog.e("replace data is \n"+t);
                    dbManager.replace(t);
                } catch (DbException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public <T> void replaceAxync(final T t, final IDBAsyncCallBack<T> callBack) {
        if (t == null) {
            return;
        }
        new AsyncTask<Void, Void, Void>() {
            String msg = null;

            @Override
            protected Void doInBackground(Void... voids) {
                try {
                    dbManager.replace(t);
                } catch (DbException e) {
                    e.printStackTrace();
                    msg = e.toString();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                callBack.onEnd(msg);
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    private <T> void addColumn(DbManager db, Class<T> tClass, String column) {
        if (TextUtils.isEmpty(column)) {
            return;
        }
        try {
            db.addColumn(tClass, column);
        } catch (DbException e) {
            e.printStackTrace();
        }
    }


    public <T> void replaceListAxync(List<T> t) {
        if (t == null) {
            return;
        }
        AsyncTask.execute(new DbListRunable<T>(t) {
            @Override
            public void run() {
                try {
                    dbManager.replace(ts);
                } catch (DbException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public <T> void findPageListByColumnAsycn(final Class<T> entityType, final String[] columns
            , final String[] ops, final String[] values, final String order, final int offset
            , final int limit, final boolean desc, final IDBAsyncCallBack<T> callBack) {
        if (entityType == null || callBack == null) {
            return;
        }
        new AsyncTask<Void, Void, List<T>>() {
            @Override
            protected List<T> doInBackground(Void... voids) {
                List<T> re = findPageListByColumn(entityType, columns, ops, values, order, offset, limit, desc);
                callBack.doOther(re);
                return re;
            }

            @Override
            protected void onPostExecute(List<T> ts) {
                if (callBack != null) {
                    callBack.findListInDB(ts);
                    callBack.onEnd(null);
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public <T> void findListByColumnAsycn(final Class<T> entityType, final String[] columns
            , final String[] ops, final String[] values, final String order, final boolean desc, final IDBAsyncCallBack<T> callBack) {
        if (entityType == null || callBack == null) {
            return;
        }
        new AsyncTask<Void, Void, List<T>>() {
            @Override
            protected List<T> doInBackground(Void... voids) {
                List<T> re = findListByColumn(entityType, columns, ops, values, order, desc);
                callBack.doOther(re);
                return re;
            }

            @Override
            protected void onPostExecute(List<T> ts) {
                if (callBack != null) {
                    callBack.findListInDB(ts);
                    callBack.onEnd(null);
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public <T> void findObjByColumnAsync(final Class<T> entityType, final String[] columns, final String[] values
            , final IDBAsyncCallBack<T> callBack) {
        if (entityType == null || callBack == null) {
            return;
        }
        new AsyncTask<Void, Void, T>() {
            @Override
            protected T doInBackground(Void... voids) {
                T t = findFirstByColumn(entityType, columns, values);
                callBack.doOther(t);
                return t;
            }

            @Override
            protected void onPostExecute(T t) {
                if (callBack != null) {
                    callBack.findObjInDB(t);
                    callBack.onEnd(null);
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public <T> void findObjByColumnAsync(final Class<T> entityType, final String[] columns
            , final String[] ops, final String[] values, final IDBAsyncCallBack<T> callBack) {
        if (entityType == null || callBack == null) {
            return;
        }
        new AsyncTask<Void, Void, T>() {
            @Override
            protected T doInBackground(Void... voids) {
                T t = findFirstByColumn(entityType, columns, ops, values);
                callBack.doOther(t);
                return t;
            }

            @Override
            protected void onPostExecute(T t) {
                if (callBack != null) {
                    callBack.findObjInDB(t);
                    callBack.onEnd(null);
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public <T> void findObjByIdAsync(final Class<T> entityType, final Object idValue
            , final IDBAsyncCallBack<T> callBack) {
        if (entityType == null || callBack == null) {
            return;
        }
        new AsyncTask<Void, Void, T>() {
            String msg;

            @Override
            protected T doInBackground(Void... voids) {
                try {
                    T t = getDbManager().findById(entityType, idValue);
                    callBack.doOther(t);
                    return t;
                } catch (Exception e) {
                    msg = e.toString();
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(T t) {
                if (callBack != null) {
                    callBack.findObjInDB(t);
                    callBack.onEnd(msg);
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public <T> void findAllAsync(final Class<T> entityType, final IDBAsyncCallBack<T> callBack){
        if(entityType==null || callBack==null){
            return;
        }
        new AsyncTask<Void,Void,List<T>>(){
            String msg=null;
            @Override
            protected List<T> doInBackground(Void... voids) {
                try {
                    List<T> ls=findAll(entityType);
                    JLog.e("info","----2"+ls);
                    return ls;
                } catch (Exception e) {
                    e.printStackTrace();
                    msg=e.toString();
                }
                return null;
            }

            @Override
            protected void onPostExecute(List<T> ts) {
                callBack.findListInDB(ts);
                callBack.onEnd(msg);
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public <T> void deleteAllAsync(final Class<T> entityType){
        if(entityType==null){
            return;
        }
        new AsyncTask<Void,Void,Void>(){
            String msg=null;
            @Override
            protected Void doInBackground(Void... voids) {
                try {
                    deleteAll(entityType);
                } catch (Exception e) {
                    e.printStackTrace();
                    msg=e.toString();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void v) {

            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public <T> List<T> findListByColumn(Class<T> entityType, String[] columns, String[] ops, String[] values, String order, boolean desc) {
        try {
            Selector<T> selector = getColumnSelector(entityType, columns, ops, values, order, 0, -1, desc);
            if (selector != null) {
                JLog.e("url="+selector.toString());
                return selector.findAll();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public <T> List<T> findPageListByColumn(Class<T> entityType, String[] columns, String[] ops
            , String[] values, String order, int offset, int limit, boolean desc) {
        try {
            Selector<T> selector = getColumnSelector(entityType, columns, ops, values, order, offset, limit, desc);
            if (selector != null) {
                JLog.e("sql->" + selector.toString());
                return selector.findAll();
            }
        } catch (Exception e) {
//            JLog.e("catch error");
            e.printStackTrace();
        }
        return null;
    }

    public <T> List<T> findListByColumn(Class<T> entityType, String[] columns, String[] values) {
        try {
            Selector<T> selector = getColumnSelector(entityType, columns, values);
            if (selector != null) {
                return selector.findAll();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public <T> T findFirstByColumn(Class<T> entityType, String[] columns, String[] values) {
        try {
            Selector<T> selector = getColumnSelector(entityType, columns, values);
            if (selector != null) {
                return selector.findFirst();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public <T> T findFirstByColumn(Class<T> entityType, String[] columns, String[] ops, String[] values) {
        try {
            Selector<T> selector = getColumnSelector(entityType, columns, ops, values);
            if (selector != null) {
                return selector.findFirst();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public <T> List<T> findAll(Class<T> cls) throws Exception {
        if (cls==null){
            return null;
        }
        return dbManager.findAll(cls);

    }

    public <T> void deleteAll(Class<T> cls) throws Exception {
        if (cls==null){
            return;
        }
        dbManager.delete(cls);

    }

    public <T> Selector<T> getColumnSelector(Class<T> entityType, String[] columns, String[] values) throws Exception {
        if (entityType == null) {
            return null;
        }
        int len = getMinLength(columns, values);
        Selector<T> selector = dbManager.selector(entityType);
        if (len > 0) {
            for (int i = 0; i < len; i++) {
                if (!TextUtils.isEmpty(columns[i])) {
                    if (i == 0) {
                        selector.where(columns[i], "=", values[i]);
                    } else {
                        selector.and(columns[i], "=", values[i]);
                    }
                } else {
                    JLog.e("add selector where has wrong -> columns:" + columns[i] + "  value:" + values[i]);
                }
            }
        }
        return selector;
    }

    public <T> Selector<T> getColumnSelector(Class<T> entityType, String[] columns, String[] ops, String[] values) throws Exception {
        if (entityType == null) {
            return null;
        }
        int len = 0;
        if (columns != null) {
            len = columns.length;
        }
//                getMinLength(columns,values);
        Selector<T> selector = dbManager.selector(entityType);
        if (len > 0) {
            String op = "=";
            String value = null;
            for (int i = 0; i < len; i++) {
                if (!TextUtils.isEmpty(columns[i])) {
                    if (values != null && i < values.length) {
                        value = values[i];
                    } else {
                        value = null;
                    }
                    if (ops != null && i < ops.length && !TextUtils.isEmpty(ops[i])) {
                        op = ops[i];
                    }
                    if (i == 0) {
                        selector.where(columns[i], op, value);
                    } else {
                        selector.and(columns[i], op, value);
                    }
                } else {
                    JLog.e("add selector where has wrong -> columns:" + columns[i] + "  op:" + op + "  value:" + value);
                }
            }
        }
        return selector;
    }

    public <T> Selector<T> getColumnSelector(Class<T> entityType, String[] columns, String[] ops
            , String[] values, String order, int offset, int limit, boolean desc) throws Exception {
        if (entityType == null) {
            return null;
        }
//        int len = columns.length;
//                getMinLength(columns,values);
        Selector<T> selector = getColumnSelector(entityType, columns, ops, values);
        if (limit > 0) {
            if (offset < 0) {
                offset = 0;
            }
            selector.limit(limit).offset(offset);
        }
        if (!TextUtils.isEmpty(order)) {
            selector.orderBy(order, desc);
        }
        return selector;
    }

    public static int getMinLength(String[] s1, String[] s2) {
        if (s1 == null || s2 == null) {
            return 0;
        }
        int l1 = s1.length;
        int l2 = s2.length;
        return l1 > l2 ? l2 : l1;
    }

    public interface IDBAsyncCallBack<T> {
        /**
         * 查找list数据的回调
         *
         * @param result
         */
        void findListInDB(List<T> result);

        void doOther(List<T> result);

        void doOther(T result);

        /**
         * 查找单个数据的回调
         */
        void findObjInDB(T result);

        void onEnd(String msg);
    }

    public static abstract class DBListAsyncCallBack<T> implements IDBAsyncCallBack<T> {
        protected long i1;

        @Override
        public final void findObjInDB(T result) {
        }

        @Override
        public final void doOther(T result) {
        }

        @Override
        public void doOther(List<T> result) {
        }

        @Override
        public void onEnd(String msg) {
        }

        public void setI1(long i){
            i1=i;
        }
    }

    public static abstract class DBObjAsyncCallBack<T> implements IDBAsyncCallBack<T> {
        @Override
        public final void findListInDB(List<T> result) {
        }

        @Override
        public final void doOther(List<T> result) {
        }

        @Override
        public void doOther(T result) {

        }

        @Override
        public void onEnd(String msg) {
        }
    }

    public static abstract class DbRunable<T> implements Runnable {
        protected T t;

        public DbRunable(T t) {
            this.t = t;
        }
    }

    public static abstract class DbListRunable<T> implements Runnable {
        protected List<T> ts;

        public DbListRunable(List<T> ts) {
            this.ts = ts;
        }
    }

    

}
